/*	MTouchSlider v0.1 <http://code.google.com/p/m-touch-slider/> 
	is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
*/

/**
 * MTouchSlider
 * @author tonylua@sina.com
 */
var MTouchSlider = (function(){
	var MData = (function(){
			function line2Upper(str){
				var re = new RegExp('\\-([a-z])','g');
				if ( !re.test(str) ) return str;
				return str.toLowerCase().replace( re, RegExp.$1.toUpperCase() ); 
			}
			function upper2Line(str){
				return str.replace(/([A-Z])/g, '-$1').toLowerCase();
			}
			function setD(ele, k, v){
				ele.setAttribute('data-'+upper2Line(k), v);
			}
			function getD(ele, k){
				var attr = ele.getAttribute('data-'+upper2Line(k)); 
				return attr||undefined;
			}
			return function(ele, k, v) {
				if (arguments.length>2){/*set*/ 
					try {
						ele.dataset[ line2Upper(k) ] = v;
					} catch(ex) {
						setD(ele, k, v);
					}
				}else{/*get*/
					try {
						return ele.dataset[ line2Upper(k) ];
					} catch(ex) {
						return getD(ele, k);
					}
				}
			};
		}()),
		_forEach = function(arr, callback){
			Array.prototype.forEach.call(arr, callback);
		},
		_ua = navigator.userAgent,
		_touchSupport = ('createTouch' in document),
		_isIOS = (_ua.match(/iPhone|iPad|iPod/i) ? true : false),
		_isMeizu = /M030|M031|M032|MEIZU/.test(navigator.userAgent),
		_isOldIOS = /OS\s[1-4]_[0-4]/.test(_ua),
		_isAndroid = ( /Android\s/.test(_ua) || _isMeizu ),
		_isOldAndroid22 = /Android\s[1-2]\.[0-2]/.test(_ua),
		_isOldAndroid23 = /Android\s[1-2]\.[0-3]/.test(_ua),
		_vendor = (/webkit/i).test(navigator.appVersion) ? "webkit": (/firefox/i).test(navigator.userAgent) ? "Moz": "opera" in window ? "O": (/MSIE/i).test(navigator.userAgent) ? "ms": "",
		_has3d = "WebKitCSSMatrix" in window && "m11" in new WebKitCSSMatrix(),
		_trnOpen = "translate" + (_has3d ? "3d(": "("),
		_trnClose = _has3d ? ",0)": ")",
		_q = function(s){return document.querySelector(s);},
		_qAll = function(s){return document.querySelectorAll(s);},
		_drawPageDot = function (clr, r){
			var cvs = document.createElement('canvas'),
				ctx = cvs.getContext('2d');
			if (!r) r=4;
			cvs.width = r*2;
			cvs.height = r*2;
			ctx.fillStyle = clr;
			ctx.beginPath();
			ctx.arc(r,r,r,Math.PI*2,0,true);
			ctx.closePath();
			ctx.fill();
			MData(cvs, 'color', clr);
			return cvs;
		},
		_getTime = function(){
			return (new Date).getTime();
		},
		_getP = function(e){
			var t = e.touches[0],
				c = e.currentTarget,
				r = c.parentNode.getClientRects()[0];			
			return {
				x: t.pageX-r.left, 
				y: t.pageY-r.top, 
				px: t.pageX,
				py: t.pageY,
				cx: t.clientX, 
				cy: t.clientY,
				sx: t.screenX,
				sy: t.screenY
			};
		},
		Const = null;
		
	Const = function(ele, config/*pageCls, barCls, dotsCls*/){
		this._cfg = config;
		this._parts = ele.querySelectorAll(config.pageCls || '.sld_page');
		this._ilng = this._parts.length;
		
		if (this._ilng<2){
			this._parts = null;
			return null;
		}
		
		this._ele = ele;
		this._bar = ele.querySelector(config.barCls || '.sld_bar');
		this._dotCtn = ele.querySelector(config.dotsCls || '.sld_dots');
		this._dots = [];
		this._curr = 0;
		this._w = this._bar.parentNode.clientWidth;
		this._needAuto = !!MData(this._ele, 'autoPlay');
		this._isRelLayout = !!MData(this._dotCtn, 'relativeLayout');
		this._autoItv = null;
		this._autoTime = MData(this._ele, 'autoTime')||3000;
		this._itvAfterTouch = null;
		this._drag_start = {time: 0, left: 0, top: 0, x: 0, y: 0, lx: 0, ly: 0};
		this._drag_end = {left: 0};
		this._directionLocked = false;
		
		this._init();
	};
	Const.prototype = {
		_init: function()
		{
			if ( this._dotCtn && this._isRelLayout ){
				this._dotCtn.style.width = 13*this._ilng + 'px';
				this._dotCtn.style.marginLeft = .5*(this._w-13*this._ilng) + 'px';
			}else{
				this._dotCtn.style.marginLeft = .5*(this._w-13*(this._ilng-1) ) + 'px';
			}
			
			for (var i=0;i<this._ilng;i++){
				this._parts[i].style.width = this._w+'px';
				
				if ( MData(this._ele, 'minHeight') )
					this._parts[i].style.minHeight = MData(this._ele, 'minHeight')+'px';
				
				var cvs = _drawPageDot( MData(this._ele, 'dotColor') );
				this._dots[i] = cvs;				
				if (this._dotCtn){
					if ( !this._isRelLayout ){
						this._cvs.style.left = 13 * i + 'px';
					}
					this._dotCtn.appendChild(cvs);
				}else{
					cvs.style.top = '0';
					cvs.style.left = (13 * i + .5*(this._w-13*(this._ilng-1) )) + 'px';
					this._bar.parentNode.insertAdjacentElement('afterBegin', cvs);
				}
			}
			
			this._bar.style.width = (this._ilng * this._w) + 'px';			
			this._setCurr(this._curr);
			this._enableAuto();
			
			var me = this;
			this._evts = {
				e_ts: function(e){	me.e_ts.call(me, e);	},
				e_tm: function(e){	me.e_tm.call(me, e);	},
				e_te: function(e){	me.e_te.call(me, e);	}
			};
			
			this._bar.addEventListener("touchstart", this._evts.e_ts);
		},
		_dragCbk: function(idx)
		{
			var funcname = MData(this._ele, 'dragCallback'), 
				func = null;
			if (funcname && window.hasOwnProperty(funcname) && typeof window[funcname] === 'function')
			{
				func = window[funcname];
				func.call(null, this._ele, this._parts[idx], idx);
			}
		},
		_enableAuto: function()
		{
			if (!this._needAuto) return;
			if (this._autoItv !== null) return;
			
			var me = this, c = this._bar, l = this._ilng;
			
			this._autoItv = window.setInterval(function(){
				var idx = me._curr + 1;
				if (idx >= l) idx = 0;
				me._doTransition(idx, true);
				me._setCurr(idx);
				me._dragCbk(idx);
			}, me._autoTime);
		},
		_disableAuto: function()
		{
			if (!this._needAuto) return;
			window.clearInterval(this._autoItv);
			this._autoItv = null;
		},
		_setCurr: function(idx)
		{
			this._curr = idx;
			_forEach(this._dots, function(a,b,c){
				a.style.opacity = .4;
			});
			if (this._dots[idx])
				this._dots[idx].style.opacity = 1;
		},
		_doTransition: function(value, tweenMode)
		{
			var d = tweenMode? /*as idx*/-value*this._w : value, 
				s = tweenMode ? 6.18 * 4 * .01 : 0;
			this._bar.style[_vendor + 'TransitionDuration'] = s + 's';
            this._bar.style[_vendor + 'Transform'] = _trnOpen + d + 'px,0' + _trnClose;
		},
		e_ts: function(e) /*touchstart*/
		{
			if (!_touchSupport) 
				e.preventDefault();
			
			this._disableAuto();			
			this._directionLocked = false;
			
			var p1 = _getP(e),
				p2 = {
					x: this._drag_end.left*1,
					y: this._bar.getClientRects()[0].top
				};
				
			this._drag_start = {
				time: _getTime(),
				left: p2.x,
				top: p2.y,
				x: parseInt(p2.x - p1.x),
				y: parseInt(p2.y - p1.y),
				lx: e.touches[0].clientX,
				ly: e.touches[0].clientY,
				point: p1
			};
			
			this._bar.addEventListener("touchmove", this._evts.e_tm);
			this._bar.addEventListener("touchend", this._evts.e_te);
			this._bar.addEventListener("touchcancel", this._evts.e_te);
		},
		e_tm: function(e) /*touchmove*/
		{
			if (!_touchSupport) 
				e.preventDefault();
			
			var p = _getP(e),
				c = e.currentTarget,
				v = this._drag_start.x + p.x;
			
			/*横纵拖动互不干扰*/
			var absDistX, 
				absDistY,
				deltaX = e.touches[0].pageX - this._drag_start.point.px,
				deltaY = e.touches[0].pageY - this._drag_start.point.py;
			if (this._directionLocked === "y") {
                return
            } else {
                if (this._directionLocked === "x") {
                    e.preventDefault()
                } else {
					absDistX = Math.abs(deltaX);
					absDistY = Math.abs(deltaY);
					if (absDistX < 4) {
						return
					}
					if (absDistY > absDistX * 0.58) {
						this._directionLocked = "y";
						return
					} else {
						e.preventDefault();
						this._directionLocked = "x";
					}
				}
            }

			this._doTransition( v );
			
			if (MData(c, 'touching') === undefined || MData(c, 'touching')*1 != 1)
				MData(c, 'touching', 1);
		},
		e_te: function(e) /*touchend*/
		{
			if (!_touchSupport) 
				e.preventDefault();
			
			this._bar.removeEventListener("touchmove", this._evts.e_tm);
			this._bar.removeEventListener("touchend", this._evts.e_te);
			this._bar.removeEventListener("touchcancel", this._evts.e_te);
			
			var c = e.currentTarget;
			MData(c, 'touching', 0);
			
			this._drag_end.left = /\((\-?[\.\d]+)px/.exec( c.style[_vendor + 'Transform'] )[1];
			
			var idx = this._curr,
				p2 = {
					x: this._drag_end.left*1,
					y: c.getClientRects()[0].top
				},				
				l = p2.x,
				tTime = _getTime() - this._drag_start.time,
				tDis = p2.x - this._drag_start.left,
				shortDis = Math.abs(tDis)<5,
				longTime = tTime > 300;
			
			if (!longTime){ /*快速拖动*/
				if (!shortDis){
					if (tDis < 0) /*left*/
						idx++;
					else /*right*/
						idx--;
				}
			}else{ /*一般拖动*/
				idx = Math.round(-l/this._w);
			}
			
			if (idx<0) idx = 0;
			if (idx>=this._ilng-1) idx = this._ilng-1;
			
			this._doTransition(idx, true);
			
			this._drag_end.left = /\((\-?[\.\d]+)px/.exec( c.style[_vendor + 'Transform'] )[1];
			
			if (idx != this._curr)
				this._dragCbk(idx);
			
			this._setCurr(idx);			
			this._enableAuto();
		}
	}; /*end of Const.prototype*/
	return Const;
}());